/**
 *
 */
package cn.xuqiudong.attachment.util;

import cn.xuqiudong.attachment.annotation.AttachmentFlag;
import cn.xuqiudong.attachment.annotation.AttachmentRelationInfo;
import cn.xuqiudong.attachment.autoconfigure.AttachmentProperties;
import cn.xuqiudong.attachment.model.AttachmentFetchResult;
import cn.xuqiudong.attachment.model.AttachmentRelation;
import cn.xuqiudong.common.base.model.BaseEntity;
import cn.xuqiudong.common.util.CommonUtils;
import cn.xuqiudong.common.util.RegexUtil;
import cn.xuqiudong.common.util.reflect.ReflectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 *  说明 :  根据注解提交实体对象中的附件信息 工具类
 *  @author Vic.xu
 * @since  2020年9月21日上午11:21:08
 */
public class AttachmentFetchByAnnotationUtil {

    private static final Logger logger = LoggerFactory.getLogger(AttachmentFetchByAnnotationUtil.class);

    /**
     * 从对象中获取附件的信息
     * 1. 从数据库中查询出来的 信息齐全 无需额外处理
     * 2. 从页面新增的（即没有id的），则需要设置table和column
     *
     * @see AttachmentFlag
     */
    public static <T extends BaseEntity> AttachmentFetchResult fetchAttachmentInfoFromObject(T t) {
        AttachmentFetchResult result = new AttachmentFetchResult();
        if (t == null) {
            return result;
        }
        try {
            Integer id = t.getId();
            Class<?> clazz = t.getClass();
            String relationDesc = getRelationDesc(clazz);
            // 向上遍历父类
            for (; clazz != Object.class; clazz = clazz.getSuperclass()) {

                Field[] fileds = clazz.getDeclaredFields();
                for (Field f : fileds) {
                    if (f.isAnnotationPresent(AttachmentFlag.class)) {
                        AttachmentFlag flag = f.getAnnotation(AttachmentFlag.class);
                        //修改为直接通过get方法获取  而不再是自省的方式 PropertyDescriptor
                        ReflectionUtils.makeAccessible(f);
                        Object value = f.get(t);
                        if (value == null || "".equals(value.toString())) {
                            continue;
                        }
                        switch (flag.value()) {
                            case SIGN:
                                if ((value.toString()).matches("\\d+")) {
                                    result.addId(Integer.parseInt(value.toString()));
                                }
                                break;
                            case SIGNS:
                                result.addIds(CommonUtils.toIntList(value.toString().split(",")));
                                break;
                            case CONTENT:
                                Integer[] arr = fetchAttachmentInfoFromObject(value.toString());
                                if (arr.length > 0) {
                                    result.addIds(new ArrayList<Integer>(Arrays.asList(arr)));
                                }
                                break;
                            case RELATION:
                                String column = getColumn(flag, f);
                                if (value instanceof List) {
                                    List<AttachmentRelation> relations = (List<AttachmentRelation>) value;
                                    relations.forEach(r -> fillOtherInfoIfRelationIdIsNull(r, id, column, relationDesc));
                                    result.addRelations(relations);
                                } else if (value instanceof AttachmentRelation) {
                                    AttachmentRelation relation = (AttachmentRelation) value;
                                    fillOtherInfoIfRelationIdIsNull(relation, id, column, relationDesc);
                                    result.addRelation(relation);
                                }
                                break;
                            default:
                                logger.info("反射{}字段{}获得的值为{}", new Object[]{t.getClass(), f.getName(), value});
                                break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(ExceptionUtils.getStackTrace(e));
        }
        return result;
    }

    /**
     * 当关系是页面新增的时候  填充其他信息
     * @param relation 关系
     * @param businessId 业务id
     * @param column 字段
     * @param table 业务表
     */
    private static void fillOtherInfoIfRelationIdIsNull(AttachmentRelation relation, Object businessId, String column, String table) {
        if (relation != null && relation.getId() == null) {
            relation.setBusinessId(String.valueOf(businessId));
            relation.setColumnName(column);
            relation.setTableName(table);
        }
    }

    /** 获得文本内容中的附件id数组 */
    public static Integer[] fetchAttachmentInfoFromObject(String content) {
        List<String> list = RegexUtil.getList(content, AttachmentProperties.textAttachmentReg, 1);
        if (list.isEmpty()) {
            return new Integer[]{};
        }
        List<Integer> intList = CommonUtils.toIntList(list.toArray(new String[0]));
        int size = intList.size();
        Integer[] arr = new Integer[size];
        for (int i = 0; i < size; i++) {
            arr[i] = intList.get(i);
        }
        return arr;
    }

    /**
     * 获取实体在关系表中的标识
     * @param clazz class
     * @return desc in relation
     */
    public static String getRelationDesc(Class clazz) {
        String relationDesc = clazz.getSimpleName();
        if (clazz.isAnnotationPresent(AttachmentRelationInfo.class)) {
            AttachmentRelationInfo attachmentRelationInfo = (AttachmentRelationInfo) clazz.getAnnotation(AttachmentRelationInfo.class);
            if (StringUtils.isNotBlank(attachmentRelationInfo.value())) {
                relationDesc = attachmentRelationInfo.value();
            }

        }
        return relationDesc;
    }

    /**
     * 获取实体 字段在关系表中的标识
     * @param flag AttachmentFlag
     * @param field Field
     * @return desc about field
     */
    public static String getColumn(AttachmentFlag flag, Field field) {
        String column = field.getName();
        if (StringUtils.isNotBlank(flag.relationColumn())) {
            column = flag.relationColumn();
        }
        return column;
    }

}
